#property copyright   "Copyright 2013,mingxinhe@gmail.com"
#property link "mingxinhe@gmail.com"


#import "mt4emailbridge.dll"
   int SendEmail(string SMTPServer, int SMTPPort, string SMTPUsername, string SMTPPassword, int RequiresSSL, string EmailFromAddress, string EmailFromName, string EmailToAddress, string EmailToName, string CCRecipient, string BCCRecipient, string Subject, string Body, int IsHtmlEmail, string AttachedFiles, int Flags);
#import

int sendEmail(string subject, string body)
{
    int rst = SendEmail("smtp.gmail.com", 587, "mingxinhe@gmail.com", "password",
    1, "mingxinhe@gmail.com", "Name", "4982913@qq.com", "Name", "", "",
    subject, body, 0, 
    "", 1);
    return (rst);
}

#define LONG          0
#define SHORT         1
#define ALL           2
#define RETRYCOUNT    10   
#define RETRYDELAY    500
#define InitStopLoss -10000000

extern string TimeFrame_Help = "0 = Current TF, 1=M1, 5=M5, 15=M15, ..., 1440=D1, 10080=W1, 43200=MN1";
extern int    TimeFrame = 0;

extern string Money_Management_Setting ="------Money Management Setting------";
extern bool   UseFixedLot = true;
extern double FixedOrderSize = 0.1;
extern double Risk.Percent.Of.Balance = 10;
extern double MaxDrawdownPercent = 100;

extern string SLTP_Setting ="------Stop Loss and Take Profit Setting------";
extern double TrailingStop.Pips = 30;
extern double TrailingStopStep.Pips = 1;
extern double StopLoss.Pips = 50;
extern double TakeProfit.Pips = 100;

extern string Other_Setting  = "------Other Setting-------";
extern int    MagicNumber=-1;
extern int    Slippage = 3;
extern bool   TextAlert = true; 
extern bool   SoundAlert = true; 
extern bool   EmailAlert = true; 
extern string SoundFileName = "Alert.wav";

extern int    MA.Fast.Period=5;
extern int    MA.Fast.Shift=1;
extern int    MA.Fast.Threshold = 18;
extern int    MA.Slow.Period=13;
extern int    MA.Slow.Shift=1;
extern int    MA.Slow.Threshold = 10;
extern string MA.Method.Desc = "0:MODE_SMA;1:MODE_EMA;2:MODE_SMMA;3:MODE_LWMA";
extern int    MA.Method=1;
extern string MA.Applied.Price.Desc = "0:PRICE_CLOSE;1:PRICE_OPEN;2:PRICE_HIGH;3:PRICE_LOW";
extern int    MA.Applied.Price = 0;

extern string  Pairs = "EURUSD,USDJPY";
StringSplit(Pairs, ",", symbolNames);
string symbolNames[];

extern int MagicNumber=20111219;
extern int Slippage = 3;

extern string start.time = "00:00"; 
extern string end.time = "23:59";
extern int GMT.offHour=0;

int digitFactor = 1;
int digitFactor = 1, lotDigits = 1,

double BasketStopLoss;

int init()
{    
    if(Bid<10 && Digits==5) { digitFactor=10;}
    if(Bid<10 && Digits==4) { digitFactor= 1;}

    if(Bid>10 && Digits==3) { digitFactor=10;}
    if(Bid>10 && Digits==2) { digitFactor= 1;}   
    
    lotDigits = MathLog(MarketInfo(Symbol(), MODE_LOTSTEP))/MathLog(0.1); 
    StopLoss.Pips *= digitFactor; 
    TakeProfit.Pips *= digitFactor; 
    TrailingStop.Pips *= digitFactor; 
    TrailingStopStep.Pips *= digitFactor; 
    
    if (MagicNumber < 0)
    {
        sub_magicnumber();
    }
}

//  Magic Number - calculated from a sum of account number and ASCII-codes from currency pair                                                                           
int sub_magicnumber()
{
     string local_currpair = Symbol();
     int local_length = StringLen (local_currpair);
     int local_asciisum = 0;
     int local_counter;

     for (local_counter = 0; local_counter < local_length -1; local_counter++)
        local_asciisum += StringGetChar (local_currpair, local_counter);
     MagicNumber = AccountNumber() + local_asciisum;   
}

 if (!GlobalVariableCheck("InitTimeFrame"))
   {
       GlobalVariableSet("InitTimeFrame", Period());
   }
   
GlobalVariableCheck
 switch( UninitializeReason() ) {
    case REASON_REMOVE:
    case REASON_ACCOUNT:
      GlobalVariablesDeleteAll(GlobalPrefix);
      ObjectDelete( obj_name_hidden_text );
      break;
  }
  
double getLots(double openPrice, double stopLossPrice)
{
    int lotDigits = MathLog(MarketInfo(Symbol(), MODE_LOTSTEP))/MathLog(0.1); 
    if (UseFixedLot)
    {
        double lot = FixedOrderSize;
    }
    else
    {        
        lot = AccountBalance()*Risk.Percent.Of.Balance/100/
             (MathAbs(openPrice - stopLossPrice)*MarketInfo(Symbol(), MODE_TICKVALUE) / MarketInfo(Symbol(), MODE_TICKSIZE));
    }
    
    if (lot < MarketInfo(symbolName, MODE_MINLOT))
    {
        Print("The lot is too small hence the minimum allowed lot is used.");
    }
    
    if (lot > MarketInfo(symbolName, MODE_MAXLOT))
    {
        Print("The lot is too big hence the maximum allowed lot is used.");
    }
    
    return (NormalizeDouble(lot, lotDigits));
}

void PrintOrder(int ticket)
{
    if(!OrderSelect(ticket, SELECT_BY_TICKET)) return (false);
    int dDigits = MarketInfo(OrderSymbol(), MODE_DIGITS);
    Print("Ask:", DoubleToStr(Ask, dDigits), " Bid:", DoubleToStr(Bid, dDigits));
    Print("Order Ticket:", OrderTicket(), " OrderLots:", OrderLots());
    Print("OpenPrice:", DoubleToStr(OrderOpenPrice(), dDigits),  " OrderStopLoss:", DoubleToStr(OrderStopLoss(), dDigits), " OrderTakeProfit:", DoubleToStr(OrderTakeProfit(), dDigits));
}

void draw_body(string id, int i, double open, double close, color col)
{
    int window = WindowFind(indicator_short_name);

    ObjectCreate(id, OBJ_TREND, window, Time[i], open, Time[i], close);
    ObjectSet(id, OBJPROP_STYLE, STYLE_SOLID);
    ObjectSet(id, OBJPROP_RAY, false);
    ObjectSet(id, OBJPROP_WIDTH, VC_BodyWidth);
    ObjectSet(id, OBJPROP_COLOR, col);
}

void draw_wick(string id, int i, double open, double close, color col)
{
    int window = WindowFind(indicator_short_name);
    
    ObjectCreate(id, OBJ_TREND, window, Time[i], open, Time[i], close);
    ObjectSet(id, OBJPROP_STYLE, STYLE_SOLID);
    ObjectSet(id, OBJPROP_RAY, false);
    ObjectSet(id, OBJPROP_WIDTH, VC_WickWidth);
    ObjectSet(id, OBJPROP_COLOR, col);
}
  
bool isTradingTime()
{
   bool isTT = false;

   datetime tm0 = TimeCurrent()+ GMT.offHour*60*60;
   datetime tm1, tm2;

   tm1 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + start.time);
   tm2 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + end.time);

   if (tm1 <= tm2) 
     isTT = tm1 <= tm0 && tm0 <= tm2;

   return (isTT);
}

 void Screenshot(string moment_name)
{
    if ( WriteScreenshots )
        WindowScreenShot(WindowExpertName()+"_"+Symbol()+"_M"+Period()+"_"+
                         Year()+"-"+Month()+"-"+Day()+"_"+
                         Hour()+"-"+Minute()+"-"+Seconds()+"_"+
                         moment_name+".gif", 1024, 768);
}  

string alertStr = "Pair:" + Symbol() + ", T/F:" +  getTimeFrame(Period()) + ", Direction: LONG, Price:" + DoubleToStr(Ask, Digits); 
string alertStr = "Pair:" + Symbol() + ", T/F:" +  getTimeFrame(Period()) + ", Direction: SHORT, Price:" + DoubleToStr(Bid, Digits); 
                 
string getTimeFrame(int _Period)
{
    switch (_Period)
    {
        case 1: return ("M1");
                break;
        case 5: return ("M5");
                break;
        case 15: return ("M15");
                break;
        case 30: return ("M30");
                break;
        case 60: return ("H1");
                break;
        case 240: return ("H4");
                break;
        case 1440: return ("D1");
                break;
        case 10080: return ("W1");
                break;
        case 43200: return ("Month");
                break;
    }
}

void doAlert(string alertStr)
{
      if (TextAlert)
      {
         Alert(alertStr);
         Print(alertStr);
      }
      if (EmailAlert)
      {
      SendMail("EA Alert:" , alertStr);  
      }
      if (SoundAlert)
      {
      PlaySound(SoundFileName);
      }   
}

//close an order with specifed ticket, if failed try again with RETRYCOUNT times
bool ExitCurrency(int ticket, string symbolName, int dir, double volume, color clr)  {
    int i, j, cmd;
    double prc, sl, tp, lots;
    string cmt;

    bool closed;

    Print("Exit("+dir+","+DoubleToStr(volume,3)+")");

    for (i=0; i<RETRYCOUNT; i++) {
        for (j=0; (j<50) && IsTradeContextBusy(); j++)
            Sleep(100);
        RefreshRates();

        if (dir == OP_BUY) {
            prc = MarketInfo(symbolName, MODE_BID);
        }
        if (dir == OP_SELL) {
            prc = MarketInfo(symbolName, MODE_ASK);
       }
        Print("Exit: prc="+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));

        closed = OrderClose(ticket,volume,prc,Slippage,clr);
        if (closed) {
            Print("Trade closed");

            return (true);
        }

        Print("Exit: error \'"+ErrorDescription(GetLastError())+"\' when exiting with "+DoubleToStr(volume,3)+" @"+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));
        Sleep(RETRYDELAY);
    }

    Print("Exit: can\'t enter after "+RETRYCOUNT+" retries");
    return (false);
}


void DrawLine(int fromIndex, int toIndex, int lineColor)
{
ObjectCreate("IndicatorName" + TimeToStr(Time[fromIndex]) + "Line",OBJ_TREND, 0, Time[fromIndex], Open[fromIndex], Time[toIndex], Open[toIndex]);
ObjectSet("IndicatorName" + TimeToStr(Time[fromIndex]) + "Line", OBJPROP_RAY, false);
ObjectSet("IndicatorName" + TimeToStr(Time[fromIndex]) + "Line", OBJPROP_COLOR, lineColor);
ObjectSet("IndicatorName" + TimeToStr(Time[fromIndex]) + "Line", OBJPROP_WIDTH, 2);
}

lotDigits = MathLog(MarketInfo(Symbol(), MODE_LOTSTEP))/MathLog(0.1); 

int orders.total, orders.BUY, orders.SELL, orders.BUYLIMIT, orders.BUYSTOP, orders.SELLLIMIT, orders.SELLSTOP;

//Count Orders and calculate the group's average entry point & spread
int CountOrders() 
{
   orders.BUY = 0;
   orders.SELL = 0;
   orders.BUYLIMIT = 0;
   orders.BUYSTOP = 0;
   orders.SELLLIMIT = 0;
   orders.SELLSTOP = 0;
   
   for( int i = OrdersTotal() - 1; i >= 0; i--) 
   {   
      if (!OrderSelect( i, SELECT_BY_POS)) continue;
      
      if( OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber ) 
      {                       
         if( OrderType() == OP_BUY ) 
         { 
             orders.BUY++; 
         }
         if( OrderType() == OP_SELL ) 
         { 
             orders.SELL++; 
         }
         if( OrderType() == OP_BUYLIMIT ) 
         { 
             orders.BUYLIMIT++; 
         }
         if( OrderType() == OP_BUYSTOP ) 
         { 
             orders.BUYSTOP++; 
         }
         if( OrderType() == OP_SELLLIMIT ) 
         { 
             orders.SELLLIMIT++; 
         }
         if( OrderType() == OP_SELLSTOP ) 
         { 
             orders.SELLSTOP++; 
         }
      }
   }
   
   orders.total = orders.BUY + orders.SELL;
   
   return(orders.total);

}

//open an order, if failed try again with RETRYCOUNT times
int DoOpenOrder(string symbolName, int dir, double volume, int stop, int take, color clr, string comment = "")  {

   double sl, tp, entryPrice;

   int ticket = 0;   

   double lots = volume;
   string info;   
   
   for (int i=0; i<RETRYCOUNT; i++) {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
         Sleep(100);
      RefreshRates();   
      
      double dAsk = MarketInfo(symbolName, MODE_ASK);
      double dBid = MarketInfo(symbolName, MODE_BID);
      double dPoint = MarketInfo(symbolName, MODE_POINT);
      double dDigits = MarketInfo(symbolName, MODE_DIGITS);


      switch(dir)  {
         case LONG:               
               entryPrice = NormalizeDouble(dAsk, dDigits);
               
               if (stop != 0) { sl = entryPrice-(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice +(take*dPoint); }
                else { tp = 0; }
                
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits) 
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
                Print(info);
                Comment(info);                
               
                ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                }
                if (ticket > 0)  
                {
                     if(OrderSelect(ticket, SELECT_BY_TICKET))
                     {
                         modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                     }
                }
                
                break;

         case SHORT:
              entryPrice = NormalizeDouble(dBid, dDigits);
              if (stop != 0) { sl = entryPrice+(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice-(take*dPoint); }
                else { tp = 0; }
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits)
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
              Print(info);
              Comment(info);
          
                ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);     
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                    
                }   
                if (ticket > 0)  
                {
                   if(OrderSelect(ticket, SELECT_BY_TICKET))
                   {
                       modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                   }
                }                      
                break;
      }
           
      if( ticket > 0 ) { return( ticket ); }
      else {
         Print("DoOpenOrder: error \'"+ErrorDescription(GetLastError())+"\' when opening entry order");
         Sleep(RETRYDELAY);      
      }
      
   }
      
   return( false );
}

// Function which splits a delimited piece of text into its
// component parts. Used to process the potentially
// tab-separated list from QC_GetMessages()
void StringSplit(string InputString, string Separator, string & ResultArray[])
{
   ArrayResize(ResultArray, 0);
   
   int lenSeparator = StringLen(Separator), NewArraySize;
   while (InputString != "") {
      int p = StringFind(InputString, Separator);
      if (p == -1) {
         NewArraySize = ArraySize(ResultArray) + 1;
         ArrayResize(ResultArray, NewArraySize);      
         ResultArray[NewArraySize - 1] = InputString;
         InputString = "";
      } else {
         NewArraySize = ArraySize(ResultArray) + 1;
         ArrayResize(ResultArray, NewArraySize);      
         ResultArray[NewArraySize - 1] = StringSubstr(InputString, 0, p);
         InputString = StringSubstr(InputString, p + lenSeparator);
         if (InputString == "") {
            ArrayResize(ResultArray, NewArraySize + 1);      
            ResultArray[NewArraySize] = "";
         }
      }     
   }
}

//close all open positions with the specified LONG or SHORT direction
void ExitAll(int direction) {       

   int i;
   
   CountOrders(); 
   if( orders.SELL != 0 && direction == SHORT) 
   {      
      while( orders.SELL != 0 ) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;       
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() ) 
            {              
                if (OrderType() == OP_SELL) { Exit( OrderTicket(), Symbol(), OP_SELL, OrderLots(), Red); }
            }
         }          
         CountOrders();                 
      }      
      return( true );
   }
   
   if( orders.BUY != 0 && direction == LONG) 
   {  
      while( orders.BUY != 0 ) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {         
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol()) {              
                if (OrderType() == OP_BUY) { Exit(OrderTicket(), Symbol(), OP_BUY, OrderLots(), Blue); }
            }
         } 
         
         CountOrders();       
      }      
      return( true );
   }   
}

//open an order, if failed try again with RETRYCOUNT times
int DoOpenOrder(int dir, double volume, int stop, int take, color clr, string comment = "")  {

   double sl, tp, entryPrice;

   int ticket = 0;   

   double lots = volume;
   string info;
   
   for (int i=0; i<RETRYCOUNT; i++) {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
         Sleep(100);
      RefreshRates();   

      switch(dir)  {
         case LONG:               
               entryPrice = NormalizeDouble(Ask, Digits);
               
               if (stop != 0) { sl = entryPrice-(stop*Point); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice +(take*Point); }
                else { tp = 0; }
                
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, Digits) 
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, Digits)  
                   + ", \nTP: " + DoubleToStr(tp, Digits);
                Print(info);
                Comment(info);                
               
                ticket = OrderSend(Symbol(), OP_BUY, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);
                if (ticket < 0)  
                {
                    ticket = OrderSend(Symbol(), OP_BUY, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                }
                if (ticket > 0)  
                {
                     if(OrderSelect(ticket, SELECT_BY_TICKET))
                     {
                         modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                     }
                }
                
                break;

         case SHORT:
              entryPrice = NormalizeDouble(Bid, Digits);
              if (stop != 0) { sl = entryPrice+(stop*Point); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice-(take*Point); }
                else { tp = 0; }
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, Digits)
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, Digits)  
                   + ", \nTP: " + DoubleToStr(tp, Digits);
              Print(info);
              Comment(info);
          
                ticket = OrderSend(Symbol(), OP_SELL, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);     
                if (ticket < 0)  
                {
                    ticket = OrderSend(Symbol(), OP_SELL, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                    
                }   
                if (ticket > 0)  
                {
                   if(OrderSelect(ticket, SELECT_BY_TICKET))
                   {
                       modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                   }
                }                      
                break;
      }
           
      if( ticket > 0 ) { return( ticket ); }
      else {
         Print("DoOpenOrder: error \'"+ErrorDescription(GetLastError())+"\' when opening entry order");
         Sleep(RETRYDELAY);      
      }
      
   }
      
   return( false );
}


for (; lastOrdersHistoryTotal < newOrdersHistoryTotal; )
{
    if (OrderSelect(lastOrdersHistoryTotal, SELECT_BY_POS, MODE_HISTORY))
    {
        if (ObjectDelete(TakeProfitEA + OrderTicket() + "TP") &&
            ObjectDelete(TakeProfitEA + OrderTicket() + "TPActive"))
        {
           lastOrdersHistoryTotal++;
        }
        else
        {
        
        }
    }
}
            
void drawLine(string name, double price, color clr)
{
   if (ObjectFind(name) == -1)
   {
       ObjectCreate(name, OBJ_HLINE, 0, 0, 0);
   }
   ObjectSet(name, OBJPROP_PRICE1, price);
   ObjectSet(name, OBJPROP_PRICE2, price);
   ObjectSet(name, OBJPROP_COLOR, clr);
}

//modify an order with specified ticket, if failed try again with RETRYCOUNT times
bool modifyOrderByPrice(int ticket, double price, double stopLoss, double takeProfit)  
{
   bool retVal = true;     
   
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) return (false);
   
   for (int i=0; i<RETRYCOUNT; i++) 
   {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
        Sleep(100);
      RefreshRates();                        

       if (MathAbs(OrderStopLoss() - stopLoss) > Point || MathAbs(OrderTakeProfit() - takeProfit) > Point)
       {              
           retVal = OrderModify(ticket, price, stopLoss, takeProfit, 0);
       }
         
      if(retVal) { return( true ); } 
      else {
         Print("DoModifyOrder: error \'"+ErrorDescription(GetLastError())+"\' when modifying order SL:", stopLoss, " TP:", takeProfit, " OrderOpenPrice:",OrderOpenPrice(), " OrderStopLoss:",OrderStopLoss());
         Sleep(RETRYDELAY);      
      }  
   }      
   return( false );
}

//return error message for each kind of errorCode
string ErrorDescription(int error_code)
{
    string error_string;

    switch( error_code ) {
        case 0:
        case 1:   error_string="no error";                                                  break;
        case 2:   error_string="common error";                                              break;
        case 3:   error_string="invalid trade parameters";                                  break;
        case 4:   error_string="trade server is busy";                                      break;
        case 5:   error_string="old version of the client terminal";                        break;
        case 6:   error_string="no connection with trade server";                           break;
        case 7:   error_string="not enough rights";                                         break;
        case 8:   error_string="too frequent requests";                                     break;
        case 9:   error_string="malfunctional trade operation (never returned error)";      break;
        case 64:  error_string="account disabled";                                          break;
        case 65:  error_string="invalid account";                                           break;
        case 128: error_string="trade timeout";                                             break;
        case 129: error_string="invalid price";                                             break;
        case 130: error_string="invalid stops";                                             break;
        case 131: error_string="invalid trade volume";                                      break;
        case 132: error_string="market is closed";                                          break;
        case 133: error_string="trade is disabled";                                         break;
        case 134: error_string="not enough money";                                          break;
        case 135: error_string="price changed";                                             break;
        case 136: error_string="off quotes";                                                break;
        case 137: error_string="broker is busy (never returned error)";                     break;
        case 138: error_string="requote";                                                   break;
        case 139: error_string="order is locked";                                           break;
        case 140: error_string="long positions only allowed";                               break;
        case 141: error_string="too many requests";                                         break;
        case 145: error_string="modification denied because order too close to market";     break;
        case 146: error_string="trade context is busy";                                     break;
        case 147: error_string="expirations are denied by broker";                          break;
        case 148: error_string="amount of open and pending orders has reached the limit";   break;
        case 149: error_string="hedging is prohibited";                                     break;
        case 150: error_string="prohibited by FIFO rules";                                  break;
        case 4000: error_string="no error (never generated code)";                          break;
        case 4001: error_string="wrong function pointer";                                   break;
        case 4002: error_string="array index is out of range";                              break;
        case 4003: error_string="no memory for function call stack";                        break;
        case 4004: error_string="recursive stack overflow";                                 break;
        case 4005: error_string="not enough stack for parameter";                           break;
        case 4006: error_string="no memory for parameter string";                           break;
        case 4007: error_string="no memory for temp string";                                break;
        case 4008: error_string="not initialized string";                                   break;
        case 4009: error_string="not initialized string in array";                          break;
        case 4010: error_string="no memory for array\' string";                             break;
        case 4011: error_string="too long string";                                          break;
        case 4012: error_string="remainder from zero divide";                               break;
        case 4013: error_string="zero divide";                                              break;
        case 4014: error_string="unknown command";                                          break;
        case 4015: error_string="wrong jump (never generated error)";                       break;
        case 4016: error_string="not initialized array";                                    break;
        case 4017: error_string="dll calls are not allowed";                                break;
        case 4018: error_string="cannot load library";                                      break;
        case 4019: error_string="cannot call function";                                     break;
        case 4020: error_string="expert function calls are not allowed";                    break;
        case 4021: error_string="not enough memory for temp string returned from function"; break;
        case 4022: error_string="system is busy (never generated error)";                   break;
        case 4050: error_string="invalid function parameters count";                        break;
        case 4051: error_string="invalid function parameter value";                         break;
        case 4052: error_string="string function internal error";                           break;
        case 4053: error_string="some array error";                                         break;
        case 4054: error_string="incorrect series array using";                             break;
        case 4055: error_string="custom indicator error";                                   break;
        case 4056: error_string="arrays are incompatible";                                  break;
        case 4057: error_string="global variables processing error";                        break;
        case 4058: error_string="global variable not found";                                break;
        case 4059: error_string="function is not allowed in testing mode";                  break;
        case 4060: error_string="function is not confirmed";                                break;
        case 4061: error_string="send mail error";                                          break;
        case 4062: error_string="string parameter expected";                                break;
        case 4063: error_string="integer parameter expected";                               break;
        case 4064: error_string="double parameter expected";                                break;
        case 4065: error_string="array as parameter expected";                              break;
        case 4066: error_string="requested history data in update state";                   break;
        case 4099: error_string="end of file";                                              break;
        case 4100: error_string="some file error";                                          break;
        case 4101: error_string="wrong file name";                                          break;
        case 4102: error_string="too many opened files";                                    break;
        case 4103: error_string="cannot open file";                                         break;
        case 4104: error_string="incompatible access to a file";                            break;
        case 4105: error_string="no order selected";                                        break;
        case 4106: error_string="unknown symbol";                                           break;
        case 4107: error_string="invalid price parameter for trade function";               break;
        case 4108: error_string="invalid ticket";                                           break;
        case 4109: error_string="trade is not allowed in the expert properties";            break;
        case 4110: error_string="longs are not allowed in the expert properties";           break;
        case 4111: error_string="shorts are not allowed in the expert properties";          break;
        case 4200: error_string="object is already exist";                                  break;
        case 4201: error_string="unknown object property";                                  break;
        case 4202: error_string="object is not exist";                                      break;
        case 4203: error_string="unknown object type";                                      break;
        case 4204: error_string="no object name";                                           break;
        case 4205: error_string="object coordinates error";                                 break;
        case 4206: error_string="no specified subwindow";                                   break;
        default:   error_string="unknown error";
    }

    return(error_string);
}

//close an order with specifed ticket, if failed try again with RETRYCOUNT times
bool Exit(int ticket, string symbolName, int dir, double volume, color clr)  {
    int i, j, cmd;
    double prc, sl, tp;
    string cmt;

    bool closed;

    Print("Exit("+dir+","+DoubleToStr(volume,3)+")");

    for (i=0; i<RETRYCOUNT; i++) {
        for (j=0; (j<50) && IsTradeContextBusy(); j++)
            Sleep(100);
        RefreshRates();

        if (dir == OP_BUY) {
            prc = MarketInfo(symbolName, MODE_BID);
        }
        if (dir == OP_SELL) {
            prc = MarketInfo(symbolName, MODE_ASK);
       }
        Print("Exit: prc="+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));

        closed = OrderClose(ticket,volume,prc,Slippage,clr);
        if (closed) {
            Print("Trade closed");

            return (true);
        }

        Print("Exit: error \'"+ErrorDescription(GetLastError())+"\' when exiting with "+DoubleToStr(volume,3)+" @"+DoubleToStr(prc,MarketInfo(symbolName, MODE_DIGITS)));
        Sleep(RETRYDELAY);
    }

    Print("Exit: can\'t enter after "+RETRYCOUNT+" retries");
    return (false);
}





void tailingStopOrders() 
{            
    if (TrailingStop.Pips <= 0) return;
    if (TrailingStopStep.Pips <= 0) return;
    
    for (int i = OrdersTotal() - 1; i >= 0; i--) 
    {
      if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;             
      if(OrderMagicNumber() == MagicNumber)
      {
         string symbolName = OrderSymbol();
         double dDigits = MarketInfo(symbolName, MODE_DIGITS);
         double dPoint = MarketInfo(symbolName, MODE_POINT);   

         double dAsk = MarketInfo(symbolName, MODE_ASK);
         double dBid = MarketInfo(symbolName, MODE_BID);
             
         if (OrderType() == OP_BUY  && TrailingStop.Pips > 0) 
         {       
            double SL = dBid - TrailingStop.Pips*dPoint;            
            if (dBid-OrderOpenPrice()>=TrailingStop.Pips*dPoint && SL >= OrderStopLoss() + TrailingStopStep.Pips*dPoint) 
            {                 
                modifyOrderByPrice(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit());
            }
         }

         if (OrderType() == OP_SELL  && TrailingStop.Pips > 0) 
         {                
            SL = dAsk + TrailingStop.Pips*dPoint;
            if (OrderOpenPrice()-dAsk>=TrailingStop.Pips*dPoint && (SL <= OrderStopLoss() - TrailingStopStep.Pips*dPoint|| OrderStopLoss() == 0)) 
            {               
                modifyOrderByPrice(OrderTicket(), OrderOpenPrice(), SL, OrderTakeProfit());
            }
         }
      }
   }
}

//open a pending order, if failed try again with RETRYCOUNT times
int DoPendingLot(string symbolName, int dir, int pendingType, double entryPrice, double volume, double sl, double tp, datetime expireTime, string comment)  {
   
   int retVal = -1;   
   double _Point = MarketInfo(symbolName, MODE_POINT); 
   double _Digits = MarketInfo(symbolName, MODE_DIGITS);
   string info;
   
   for (int i=0; i<RETRYCOUNT; i++) {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
         Sleep(100);
      RefreshRates();   

      switch(dir)  {
         case LONG:                               
                                              
                info = "Type: " + pendingType + ", \nentryPrice: " + DoubleToStr(entryPrice, _Digits) + ", \nAsk " + DoubleToStr(MarketInfo(symbolName, MODE_ASK),_Digits)
                   + ", \nLots " + DoubleToStr(volume, 2) + " , \nStopLoss: " + DoubleToStr(sl, _Digits)  + ", \nTakeProfit: " + DoubleToStr(tp, _Digits)
                    + ", \nStopLevel: " + MarketInfo(symbolName, MODE_STOPLEVEL);
                Print(info);
                Comment(info);                
                               
                retVal = OrderSend(symbolName, pendingType, volume, entryPrice, Slippage, sl, tp, comment, MagicNumber, expireTime, Olive);
                if (retVal < 0)  
                {
                    retVal = OrderSend(symbolName, pendingType, volume, entryPrice, Slippage, 0, 0, comment, MagicNumber, expireTime, Blue);
                    modifyOrderByPrice(retVal, entryPrice, sl, tp);
                }
                break;

         case SHORT:               
                
                info = "Type: " + pendingType + ", \nentryPrice: " + DoubleToStr(entryPrice, _Digits) + ", \nBid " + DoubleToStr(MarketInfo(symbolName, MODE_BID),_Digits)
                   + ", \nLots " + DoubleToStr(volume, 2) + " , \nStopLoss: " + DoubleToStr(sl, _Digits) + ", \nTakeProfit: " + DoubleToStr(tp, _Digits)                     
                   + ", \nStopLevel: " + MarketInfo(symbolName, MODE_STOPLEVEL);
              Print(info);
              Comment(info);
          
                retVal = OrderSend(symbolName, pendingType, volume, entryPrice, Slippage, sl, tp, comment, MagicNumber, expireTime, MediumVioletRed);
                if (retVal < 0)  
                {
                    retVal = OrderSend(symbolName, pendingType, volume, entryPrice, Slippage, 0, 0, comment, MagicNumber, expireTime, Red);
                    modifyOrderByPrice(retVal, entryPrice, sl, tp);           
                }
                break;
      }
           
      if( retVal > 0 ) { return( retVal ); }
      else {
         Print("DoPending pendingType:", pendingType, " error: \'"+ErrorDescription(GetLastError())+"\' when setting entry order");
         Sleep(RETRYDELAY);      
      }
      
   }
      
   return( retVal );
}

double getLots(string symbolName)
{
    int lotDigits = MathLog(MarketInfo(symbolName, MODE_LOTSTEP))/MathLog(0.1); 
    if (UseFixedLot)
    {
        double lot = FixedOrderSize;
    }
    else
    {        
        lot = AccountBalance()*Risk.Percent.Of.Balance/100/MarketInfo(symbolName, MODE_MARGINREQUIRED);
    }
    
    if (lot < MarketInfo(symbolName, MODE_MINLOT))
    {
        Print("The lot is too small hence the minimum allowed lot is used.");
    }
    
    if (lot > MarketInfo(symbolName, MODE_MAXLOT))
    {
        Print("The lot is too big hence the maximum allowed lot is used.");
    }
    
    return (NormalizeDouble(lot, lotDigits));
}

int CountOrders(string symbolName) 
{
   orders.BUY = 0;
   orders.SELL = 0;
   orders.BUYLIMIT = 0;
   orders.BUYSTOP = 0;
   orders.SELLLIMIT = 0;
   orders.SELLSTOP = 0;
   
   for( int i = OrdersTotal() - 1; i >= 0; i--) 
   {   
      if (!OrderSelect( i, SELECT_BY_POS)) continue;
      
      if( OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderSymbol() == symbolName) 
      {                       
         if( OrderType() == OP_BUY ) 
         { 
             orders.BUY++; 
         }
         if( OrderType() == OP_SELL ) 
         { 
             orders.SELL++; 
         }
         if( OrderType() == OP_BUYLIMIT ) 
         { 
             orders.BUYLIMIT++; 
         }
         if( OrderType() == OP_BUYSTOP ) 
         { 
             orders.BUYSTOP++; 
         }
         if( OrderType() == OP_SELLLIMIT ) 
         { 
             orders.SELLLIMIT++; 
         }
         if( OrderType() == OP_SELLSTOP ) 
         { 
             orders.SELLSTOP++; 
         }
      }
   }
   
   orders.total = orders.BUY + orders.SELL;
   
   return(orders.total);

}



//close all open positions with the specified LONG or SHORT direction
void ExitAll(int direction, string symbolName) {       

   int i;
   
   CountOrders(symbolName); 
   if( orders.SELL != 0 && direction == SHORT) 
   {      
      while( orders.SELL != 0 ) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;       
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == symbolName ) 
            {              
                if (OrderType() == OP_SELL) { Exit( OrderTicket(), symbolName, OP_SELL, OrderLots(), Red); }
            }
         }          
         CountOrders(symbolName);                 
      }      
      return( true );
   }
   
   if( orders.BUY != 0 && direction == LONG) 
   {  
      while( orders.BUY != 0 ) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {         
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == symbolName) {              
                if (OrderType() == OP_BUY) { Exit(OrderTicket(), symbolName, OP_BUY, OrderLots(), Blue); }
            }
         } 
         
         CountOrders(symbolName);       
      }      
      return( true );
   }   
}


bool DeletePendings(int direction) {
   
   bool pendings;
   int i;
   
   CountOrders(); 
   if( (orders.SELLLIMIT != 0 || orders.SELLSTOP != 0) && direction == SHORT) 
   {
      while(orders.SELLLIMIT != 0 || orders.SELLSTOP != 0) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
            
            pendings = OrderType() == OP_SELLLIMIT || OrderType() == OP_SELLSTOP;            
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() && pendings ) 
            {              
               OrderDelete( OrderTicket() );
            }
         }          
         CountOrders();                 
      }
      
      return( true );
   }
   
   if ((orders.BUYLIMIT != 0 || orders.BUYSTOP != 0) && direction == LONG) 
   {      
      while((orders.BUYLIMIT != 0 || orders.BUYSTOP != 0)) 
      {
         for(i = OrdersTotal() - 1; i >= 0; i--) 
         {         
            if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
  
            pendings = OrderType() == OP_BUYLIMIT || OrderType() == OP_BUYSTOP;
            if( OrderMagicNumber() == MagicNumber && OrderSymbol() == Symbol() && pendings) 
            {              
               OrderDelete(OrderTicket());
            }
         }          
         CountOrders();       
      }
      
      return( true );
   }   
}

// *************************************************************************************
// Service function for splitting a string into an array of values. For example,
// it can be used to take a comma-separated line (read using ReadLineFromFile() etc)
// and break it into an array of its comma-delimited parts.
// Example usage is:
//      string Results[];
//      StringSplit("abc,def,ghi", ",", Results);
// *************************************************************************************
bool SplitString(string stringValue, string separatorSymbol, string& results[], int expectedResultCount = 0)
{
   if (StringFind(stringValue, separatorSymbol) < 0)
   {// No separators found, the entire string is the result.
      ArrayResize(results, 1);
      results[0] = stringValue;
   }
   else
   {   
      int separatorPos = 0;
      int newSeparatorPos = 0;
      int size = 0;

      while(newSeparatorPos > -1)
      {
         size = size + 1;
         newSeparatorPos = StringFind(stringValue, separatorSymbol, separatorPos);
         
         ArrayResize(results, size);
         if (newSeparatorPos > -1)
         {
            if (newSeparatorPos - separatorPos > 0)
            {  // Evade filling empty positions, since 0 size is considered by the StringSubstr as entire string to the end.
               results[size-1] = StringSubstr(stringValue, separatorPos, newSeparatorPos - separatorPos);               
            }
         }
         else
         {  // Reached final element.
            results[size-1] = StringSubstr(stringValue, separatorPos, 0);
         }         
         results[size-1] = StringTrimLeft(StringTrimRight(results[size-1]));
         
         separatorPos = newSeparatorPos + 1;
      }
   }   
   
   if (expectedResultCount == 0 || expectedResultCount == ArraySize(results))
   {  // Results OK.
      return (true);
   }
   else
   {  // Results are WRONG.
      Print("ERROR - size of parsed string not expected.");
      return (false);
   }
}



// Import of functions from User32. If their purpose isn't pretty much immediately

// clear, then documenting it here frankly isn't going to help much. Requires 

// "Allow DLL imports" to be turned on.

#import "user32.dll"

   int RegisterWindowMessageA(string MessageName);

   int PostMessageA(int hwnd, int msg, int wparam, string Name);

   void keybd_event(int VirtualKey, int ScanCode, int Flags, int ExtraInfo);

#import





// The hWnd parameter for all these functions is obtained using WindowHandle().

// For example, an EA/script can get the handle of its own chart using

// WindowHandle(Symbol(), 0). If the EA/script knows that another chart 

// is open, then its handle can be obtained using the known symbol and

// timeframe. Unpredictable behaviour if there are multiple charts for 

// the same symbol and timeframe. AutomaticallyAcceptDefaults clears

// the configuration window for the new indicator/EA/script by simulating

// a press of the Enter key after a small wait. A longer wait might 

// prove to be more robust. None of this is for the faint-hearted...



void StartStandardIndicator(int hWnd, string IndicatorName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 13, IndicatorName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void StartCustomIndicator(int hWnd, string IndicatorName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 15, IndicatorName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void StartEA(int hWnd, string EAName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 14, EAName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void StartScript(int hWnd, string ScriptName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 16, ScriptName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void ClearConfigDialog()
{

   Sleep(100);

   keybd_event(13, 0, 0, 0);

}

void drawArrow(int & arrowID, int barIdx, color arrowColor, double Range, int arrowCode)
{      
   string arrowIDStr = DoubleToStr(arrowID,0);  
   if (arrowCode == 233)
   {
       double price = Low[barIdx] - Range*0.5;
   }
   else if (arrowCode == 234)
   {
       price = High[barIdx] + Range*0.5;
   }    
   
    ObjectCreate(arrowIDStr,OBJ_ARROW,0,Time[barIdx],price);
    ObjectSet(arrowIDStr,OBJPROP_ARROWCODE,arrowCode);
    ObjectSet(arrowIDStr,OBJPROP_COLOR, arrowColor);   
    ObjectSet(arrowIDStr,OBJPROP_WIDTH, 1);
        
    arrowID++;
}

//open an order, if failed try again with RETRYCOUNT times
int DoOpenOrder(string symbolName, int dir, double volume, int stop, int take, color clr, string comment = "")  {

   double sl, tp, entryPrice;

   int ticket = 0;   

   double lots = volume;
   string info;
   
   double dAsk = MarketInfo(symbolName, MODE_ASK);
   double dBid = MarketInfo(symbolName, MODE_BID);
   double dPoint = MarketInfo(symbolName, MODE_POINT);
   double dDigits = MarketInfo(symbolName, MODE_DIGITS);
   
   for (int i=0; i<RETRYCOUNT; i++) {
     for (int j=0; (j<50) && IsTradeContextBusy(); j++)
         Sleep(100);
      RefreshRates();   

      switch(dir)  {
         case LONG:               
               entryPrice = NormalizeDouble(dAsk, dDigits);
               
               if (stop != 0) { sl = entryPrice-(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice +(take*dPoint); }
                else { tp = 0; }
                
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits) 
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
                Print(info);
                Comment(info);                
               
                ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_BUY, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                }
                if (ticket > 0)  
                {
                     if(OrderSelect(ticket, SELECT_BY_TICKET))
                     {
                         modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                     }
                }
                
                break;

         case SHORT:
              entryPrice = NormalizeDouble(dBid, dDigits);
              if (stop != 0) { sl = entryPrice+(stop*dPoint); }
                else { sl = 0; }
                if (take != 0) { tp = entryPrice-(take*dPoint); }
                else { tp = 0; }
                
                info = "Type: " + dir + ", \nentryPrice: " + DoubleToStr(entryPrice, dDigits)
                   + ", \nLots " + DoubleToStr(lots, 2) + " , \nStop: " + DoubleToStr(sl, dDigits)  
                   + ", \nTP: " + DoubleToStr(tp, dDigits);
              Print(info);
              Comment(info);
          
                ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, sl, tp, comment, MagicNumber, 0, clr);     
                if (ticket < 0)  
                {
                    ticket = OrderSend(symbolName, OP_SELL, lots, entryPrice, Slippage, 0, 0, comment, MagicNumber, 0, clr);                    
                    
                }   
                if (ticket > 0)  
                {
                   if(OrderSelect(ticket, SELECT_BY_TICKET))
                   {
                       modifyOrderByPrice(ticket, OrderOpenPrice(), sl, tp);
                   }
                }                      
                break;
      }
           
      if( ticket > 0 ) { return( ticket ); }
      else {
         Print("DoOpenOrder: error \'"+ErrorDescription(GetLastError())+"\' when opening entry order");
         Sleep(RETRYDELAY);      
      }
      
   }
      
   return( false );
}

void getHighLowOfPreDay(double &lastDayHigh, double &lastDayLow)
{
    int curWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, 0) + GMT.OffHour*60*60);
    //Print("curWeekDay:",curWeekDay);
    int idxForEnd = 1;
    int preWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForEnd)  + GMT.OffHour*60*60);
    while (curWeekDay == preWeekDay)
    {
        preWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForEnd) + GMT.OffHour*60*60);
        idxForEnd++;
    }
    //Print("preWeekDay:",preWeekDay, " ", TimeToStr(iTime(NULL, PERIOD_H1, idxForEnd-1) + GMT.OffHour*60*60));
    int idxForBegin = idxForEnd + 1;
    int prePreWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForBegin) + GMT.OffHour*60*60);
    while (preWeekDay == prePreWeekDay)
    {
        prePreWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForBegin) + GMT.OffHour*60*60);
        idxForBegin ++;
    } 
    
    if (preWeekDay == 0 || prePreWeekDay == 0)
    {
        preWeekDay = prePreWeekDay;
        idxForBegin++;
        prePreWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForBegin) + GMT.OffHour*60*60);
        while (preWeekDay == prePreWeekDay)
        {
            prePreWeekDay = TimeDayOfWeek(iTime(NULL, PERIOD_H1, idxForBegin)  + GMT.OffHour*60*60);
            idxForBegin++;
        } 
    }        
    idxForBegin -= 2;
    idxForEnd--;
    
    //Comment(TimeToStr(iTime(NULL, PERIOD_H1, idxForBegin)), " ",TimeToStr(iTime(NULL, PERIOD_H1, idxForEnd)));
    lastDayHigh = iHighest(NULL, PERIOD_H1, MODE_HIGH, idxForBegin - idxForEnd + 1, idxForEnd);
    lastDayLow = iLowest(NULL, PERIOD_H1, MODE_LOW, idxForBegin - idxForEnd + 1, idxForEnd);
}


double getBasketProfit()
{
    double BasketProfit = 0;
    for (int i = OrdersTotal() - 1; i >= 0; i--) 
    {
        if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
                
        if(OrderMagicNumber() == Magic) 
        {
            BasketProfit += OrderProfit();        
        }
    }
    
    return (BasketProfit);
}

void basketTrailingStop()
{
    double totalProfit = getBasketProfit();
    
    if (orders.total > 0)
    {
        if (UseTrailingStop)
        {            
            if (totalProfit >= TrailingStop.Dollar)
            {                
                if (BasketStopLoss == InitStopLoss)
                {
                    BasketStopLoss = 0;
                }
                else if (totalProfit - TrailingStop.Dollar >= BasketStopLoss + TrailingStopStep.Dollar)
                {
                    BasketStopLoss =  totalProfit - TrailingStop.Dollar;
                }                                
            }
        }                  
    }
    else
    {
        BasketStopLoss = InitStopLoss;
    }
    
    if (totalProfit <= BasketStopLoss && BasketStopLoss >= 0)
    {
         ExitAll(LONG, Symbol());        
         ExitAll(SHORT, Symbol());
         BasketStopLoss = InitStopLoss;
    }
}

// Import of functions from User32. If their purpose isn't pretty much immediately

// clear, then documenting it here frankly isn't going to help much. Requires 

// "Allow DLL imports" to be turned on.

#import "user32.dll"

   int RegisterWindowMessageA(string MessageName);

   int PostMessageA(int hwnd, int msg, int wparam, string Name);

   void keybd_event(int VirtualKey, int ScanCode, int Flags, int ExtraInfo);

#import





// The hWnd parameter for all these functions is obtained using WindowHandle().

// For example, an EA/script can get the handle of its own chart using

// WindowHandle(Symbol(), 0). If the EA/script knows that another chart 

// is open, then its handle can be obtained using the known symbol and

// timeframe. Unpredictable behaviour if there are multiple charts for 

// the same symbol and timeframe. AutomaticallyAcceptDefaults clears

// the configuration window for the new indicator/EA/script by simulating

// a press of the Enter key after a small wait. A longer wait might 

// prove to be more robust. None of this is for the faint-hearted...
extern bool   AutomaticallyAcceptDefaults = true;
StartCustomIndicator(WindowHandle(Symbol(), 0), TMAmCG_FileName, AutomaticallyAcceptDefaults);

void StartStandardIndicator(int hWnd, string IndicatorName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 13, IndicatorName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}

//close all open positions with the specified LONG or SHORT direction
void ExitAll(int direction) {       
    for (int i = OrdersTotal() - 1; i >= 0; i--) {
      OrderSelect(i, SELECT_BY_POS, MODE_TRADES);         
    
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) {
         if (OrderType() == OP_BUY && direction == LONG) { Exit(OrderTicket(), LONG, OrderLots(), Blue); }
         if (OrderType() == OP_SELL && direction == SHORT) { Exit( OrderTicket(), SHORT, OrderLots(), Red); }
      }
   }
}

void StartCustomIndicator(int hWnd, string IndicatorName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 15, IndicatorName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void StartEA(int hWnd, string EAName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 14, EAName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void StartScript(int hWnd, string ScriptName, bool AutomaticallyAcceptDefaults = false)

{

   int MessageNumber = RegisterWindowMessageA("MetaTrader4_Internal_Message");

   PostMessageA(hWnd, MessageNumber, 16, ScriptName);

   if (AutomaticallyAcceptDefaults) ClearConfigDialog();

}



void ClearConfigDialog()

{

   Sleep(100);

   keybd_event(13, 0, 0, 0);

}


extern string Trade_Setting ="------Money Management Setting------";
extern bool   LongTrades = true;
extern bool   ShortTrades = true;
extern int    ExpireAfterNMinutes = 90;  
extern string Sun.StartTime = "00:00"; 
extern string Sun.EndTime = "23:59";
extern string Mon.StartTime = "00:00"; 
extern string Mon.EndTime = "23:59";
extern string Tue.StartTime = "00:00"; 
extern string Tue.EndTime = "23:59";
extern string Wen.StartTime = "00:00"; 
extern string Wen.EndTime = "23:59";
extern string Thu.StartTime = "00:00"; 
extern string Thu.EndTime = "23:59";
extern string Fri.StartTime = "00:00"; 
extern string Fri.EndTime = "23:59";
extern int    GMT.offHour=0;

bool isDayTradingTime(int weekDay, string start.time, string end.time)
{
   bool isTT = false;

   datetime tm0 = TimeCurrent()+ GMT.offHour*60*60;
   datetime tm1, tm2;

   tm1 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + start.time);
   tm2 = StrToTime(TimeToStr(tm0, TIME_DATE) + " " + end.time);

   if (tm1 <= tm2) 
     isTT = tm1 <= tm0 && tm0 <= tm2 && TimeDayOfWeek(tm0) == weekDay;

   return (isTT);
}

void drawText(string name, int window, datetime time1, double price1, string text, color textColor)
{
    ObjectCreate(name, OBJ_TEXT, window, time1, price1);
    ObjectSet(name, OBJPROP_PRICE1, price1);
    ObjectSetText(name, text, 10, "Times New Roman", textColor);
}

void drawLabel(string name, int window, int x, int y, string text, color textColor)
{
    if (ObjectFind(name) < 0)
    {
        ObjectCreate(name, OBJ_LABEL, window, 0, 0);
    }
    ObjectSet(name, OBJPROP_XDISTANCE, x);
    ObjectSet(name, OBJPROP_YDISTANCE, y);
    ObjectSetText(name, text, 10, "Times New Roman", textColor);
}



/**
* search for the string needle in the string haystack and replace all
* occurrecnes with replace.
*/
string stringReplace(string haystack, string needle, string replace=""){
   string left, right;
   int start=0;
   int rlen = StringLen(replace);
   int nlen = StringLen(needle);
   while (start > -1){
      start = StringFind(haystack, needle, start);
      if (start > -1){
         if(start > 0){
            left = StringSubstr(haystack, 0, start);
         }else{
            left="";
         }
         right = StringSubstr(haystack, start + nlen);
         haystack = left + replace + right;
         start = start + rlen;
      }
   }
   return (haystack);  
}